//============================================================================
// Name        : cpp_async_callback.cpp
// Author      : darkflash
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <functional>
#include <future>
#include <string>
#include <sstream>
#include <iostream>
#include <thread>

std::string asyncMethod(std::string asyncName){
	for(int i=0;i<100;i++){
		std::stringstream a;
		a << i;
		std::cout << asyncName + ": " + a.str()<< std::endl;
	}

	return std::string(asyncName + " callback");
}

void asyncPromiseMethod(std::future<std::string>& fut){
	std::string s = fut.get();

	std::string callback = asyncMethod(s);

	std::cout << callback << std::endl;
}

void asyncPackagedTaskMethod(std::future<std::string> fut){
	std::string callback = fut.get();
	std::cout << callback << std::endl;
}

void asyncFuture(){
	std::future<std::string> fut1 = std::async(std::launch::async, asyncMethod, "async1");
	std::future<std::string> fut2 = std::async(std::launch::async, asyncMethod, "async2");

	for(int i=0;i<100;i++){
		std::stringstream a;
		a << i;
		std::cout << "main: " + a.str() << std::endl;
	}

	std::string callback1 = fut1.get();
	std::string callback2 = fut2.get();

	std::cout << callback1 << std::endl;
	std::cout << callback2 << std::endl;
}

void asyncPromise(){
	std::promise<std::string> prom1;
	std::promise<std::string> prom2;

	std::future<std::string> fut1 = prom1.get_future();
	std::future<std::string> fut2 = prom2.get_future();

	std::thread th1 (asyncPromiseMethod, std::ref(fut1));
	std::thread th2 (asyncPromiseMethod, std::ref(fut2));

	prom1.set_value("async1");
	prom2.set_value("async2");

	for(int i=0;i<100;i++){
		std::stringstream a;
		a << i;
		std::cout << "main: " + a.str() << std::endl;
	}

	th1.join();
	th2.join();
}

void asyncPackagedTask(){
	std::packaged_task<std::string(std::string)> tsk1(asyncMethod);
	std::packaged_task<std::string(std::string)> tsk2(asyncMethod);

	std::future<std::string> fut1 = tsk1.get_future();
	std::future<std::string> fut2 = tsk2.get_future();

	std::thread th1(std::move(tsk1), "async1");
	std::thread th2(std::move(tsk2), "async2");

	for(int i=0;i<100;i++){
		std::stringstream a;
		a << i;
		std::cout << "main: " + a.str() << std::endl;
	}

	std::string callback1 = fut1.get();
	std::string callback2 = fut2.get();

	std::cout << callback1 << std::endl;
	std::cout << callback2 << std::endl;

	th1.join();
	th2.join();
}


int main() {
	//asyncFuture();
	//asyncPromise();
	//asyncPackagedTask();

	return 0;
}
